package com.dituhui.tool.gis;

import java.util.ArrayList;
import java.util.List;

import com.dituhui.tool.util.StringUtil;
import com.supermap.analyst.spatialanalyst.ProximityAnalyst;
import com.supermap.analyst.spatialanalyst.StatisticsPoint;
import com.supermap.data.GeoLine;
import com.supermap.data.GeoPoint;
import com.supermap.data.Geometrist;
import com.supermap.data.Geometry;
import com.supermap.data.Point2D;
import com.supermap.data.Point2Ds;
import com.supermap.data.ResampleType;

/**
 * 线对象
 * 
 * @author liweigu
 * 
 */
public class Line {
	// 点列表
	private List<Point> points = new ArrayList<Point>();

	/**
	 * 构造函数
	 */
	public Line() {
	}

	/**
	 * 构造函数
	 * 
	 * @param points 点串。points应包含至少2个点。
	 */
	public Line(List<Point> points) {
		if (points == null || points.size() < 2) {
			throw new IllegalArgumentException("points必须包含至少2个点");
		}
		this.points = points;
	}

	/**
	 * 获取点列表
	 * 
	 * @return 点列表
	 */
	public List<Point> getPoints() {
		return this.points;
	}

	/**
	 * 设置点列表
	 * 
	 * @param points 点列表
	 */
	public void setPoints(List<Point> points) {
		this.points = points;
	}

	/**
	 * 获取长度
	 * 
	 * @return 长度。单位是米。
	 */
	public double getLength() {
		double length = 0;

		if (this.points != null && this.points.size() > 1) {
			// 拷贝一份，然后将坐标转换为摩卡托
			Line copiedLine = (Line) this.clone();
			List<Point> copiedPoints = copiedLine.points;
			for (int i = 1; i < copiedPoints.size(); i++) {
				Point startPoint = copiedPoints.get(i - 1);
				Point endPoint = copiedPoints.get(i);
				if (startPoint != null) {
					double distance = startPoint.distanceTo(endPoint);
					length += distance;
				}
			}
		}

		return length;
	}

	/**
	 * 重采样。依赖Object Java。
	 */
	public void resample(double tolerance) {
		Point2Ds point2Ds = new Point2Ds();
		for (Point point : this.points) {
			point2Ds.add(new Point2D(point.getX(), point.getY()));
		}
		GeoLine geoLine = new GeoLine(point2Ds);
		ResampleType resampleType = ResampleType.RTGENERAL;
		// resampleType = ResampleType.RTBEND;
		Geometry geometry = Geometrist.resample(geoLine, resampleType, tolerance);
		geoLine = (GeoLine) geometry;
		point2Ds = geoLine.getPart(0);
		this.points = new ArrayList<Point>();
		for (int i = 0; i < point2Ds.getCount(); i++) {
			Point2D point2D = point2Ds.getItem(i);
			this.points.add(new Point(point2D.getX(), point2D.getY()));
		}
	}

	/**
	 * 抽稀。依赖Object Java。
	 * 
	 * @param radius 合并点的计算半径
	 * @return 抽稀是否成功
	 */
	public boolean rarefy(double radius) {
		boolean isSuccess = false;

		if (this.points != null) {
			StatisticsPoint[] sourcePoints = new StatisticsPoint[this.points.size()];
			for (int i = 0; i < this.points.size(); i++) {
				Point point = this.points.get(i);
				sourcePoints[i] = new StatisticsPoint(new Point2D(point.getX(), point.getY()));
			}
			StatisticsPoint[] statisticsPoints = ProximityAnalyst.rarefyPoints(sourcePoints, radius);
			if (statisticsPoints != null) {
				List<Point> resultPoints = new ArrayList<Point>();
				for (StatisticsPoint statisticsPoint : statisticsPoints) {
					Point point = new Point(statisticsPoint.getPoint().getX(), statisticsPoint.getPoint().getY());
					resultPoints.add(point);
				}
				this.points = resultPoints;
				isSuccess = true;
			}
		}

		return isSuccess;
	}

	/**
	 * 计算点线的距离
	 * 
	 * @param point 另一个点
	 * @return 距离，单位是米
	 */
	public double distanceTo(Point point) {
		List<Point> linePoints = this.getPoints();
		GeoPoint geoPoint = new GeoPoint(point.getY(), point.getX());
		GeoLine geoLine = new GeoLine();
		Point2Ds point2Ds = new Point2Ds();
		for (Point p : linePoints) {
			point2Ds.add(new Point2D(p.getY(), p.getX()));
		}
		geoLine.addPart(point2Ds);
		// TODO 坐标转换？
		double distance = Geometrist.distance(geoPoint, geoLine);
		return distance;
	}

	@Override
	/**
	 * 复制线对象
	 * 
	 * @return 线对象
	 */
	public Object clone() {
		Line copiedLine = new Line();

		if (this.points != null) {
			List<Point> copiedPoints = new ArrayList<Point>();
			for (Point point : this.points) {
				Point copiedPoint = new Point(point);
				copiedPoints.add(copiedPoint);
			}
			copiedLine.setPoints(copiedPoints);
		}

		return copiedLine;
	}

	/**
	 * toString方法
	 * 
	 * @return String
	 */
	@Override
	public String toString() {
		if (this.points == null) {
			return StringUtil.EMPTY;
		} else {
			StringBuilder stringBuilder = new StringBuilder();
			boolean isFirst = true;
			for (Point point : this.points) {
				stringBuilder.append(point.toString());
				if (isFirst) {
					isFirst = false;
				} else {
					stringBuilder.append(StringUtil.SEMICOLON);
				}
			}
			return stringBuilder.toString();
		}
	}

	/**
	 * 获取哈希值
	 * 
	 * @return 哈希值
	 */
	@Override
	public int hashCode() {
		return this.toString().hashCode();
	}
}
